import 'package:flutter/material.dart';

/// 文本装饰样式
enum UnderlineStyle {
  solid,   // 实线
  dashed,  // 虚线
  dotted,  // 点线
  wavy,    // 波浪线
}

/// 注释位置
enum NotePosition {
  above,  // 文本上方
  below,  // 文本下方
}

/// 文本片段装饰
class TextSpanDecoration {
  final int start;          // 开始位置
  final int end;           // 结束位置
  final String? note;      // 注释文本
  final NotePosition notePosition; // 注释位置
  final Color color;       // 装饰颜色
  final UnderlineStyle style; // 下划线样式
  final double thickness;    // 线条粗细
  final double spacing;     // 装饰与文本的间距
  final double noteSpacing; // 注释与文本的间距

  const TextSpanDecoration({
    required this.start,
    required this.end,
    this.note,
    this.notePosition = NotePosition.above,
    this.color = Colors.black,
    this.style = UnderlineStyle.solid,
    this.thickness = 1.0,
    this.spacing = 2.0,
    this.noteSpacing = 4.0,
  });
}

/// 文本渲染组件
class DecoratedTextRenderer extends StatelessWidget {
  final String text;                        // 文本内容
  final List<TextSpanDecoration> spans;     // 文本装饰
  final TextStyle textStyle;                // 文本样式
  final TextStyle noteStyle;                // 注释文本样式
  final double minLineSpacing;              // 最小行间距
  final bool showNotes;                     // 是否显示注释

  const DecoratedTextRenderer({
    required this.text,
    required this.spans,
    this.textStyle = const TextStyle(),
    this.noteStyle = const TextStyle(fontSize: 12),
    this.minLineSpacing = 8.0,  // 确保有足够空间显示注释
    this.showNotes = true,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: TextDecorationPainter(
        text: text,
        spans: spans,
        textStyle: textStyle,
        noteStyle: noteStyle,
        minLineSpacing: minLineSpacing,
        showNotes: showNotes,
      ),
    );
  }
}

class TextDecorationPainter extends CustomPainter {
  final String text;
  final List<TextSpanDecoration> spans;
  final TextStyle textStyle;
  final TextStyle noteStyle;
  final double minLineSpacing;
  final bool showNotes;

  late final TextPainter _textPainter;
  late final List<TextPainter> _notePainters;

  TextDecorationPainter({
    required this.text,
    required this.spans,
    required this.textStyle,
    required this.noteStyle,
    required this.minLineSpacing,
    required this.showNotes,
  }) {
    // 初始化文本绘制器
    _textPainter = TextPainter(
      text: TextSpan(text: text, style: textStyle),
      textDirection: TextDirection.ltr,
    );

    // 初始化注释绘制器
    _notePainters = spans
        .where((span) => span.note != null && showNotes)
        .map((span) => TextPainter(
      text: TextSpan(
        text: span.note,
        style: noteStyle,
      ),
      textDirection: TextDirection.ltr,
    ))
        .toList();
  }

  @override
  void paint(Canvas canvas, Size size) {
    // 布局文本
    _textPainter.layout(maxWidth: size.width);

    // 绘制文本
    _textPainter.paint(canvas, Offset.zero);

    // 绘制每个文本片段的装饰
    for (final span in spans) {
      _drawDecoration(canvas, span);
    }
  }

  void _drawDecoration(Canvas canvas, TextSpanDecoration span) {
    // 获取文本片段的范围
    final textRange = TextRange(start: span.start, end: span.end);
    final boxes = _textPainter.getBoxesForSelection(
      TextSelection(baseOffset: span.start, extentOffset: span.end),
    );

    for (final box in boxes) {
      // 绘制下划线
      _drawUnderline(canvas, box, span);

      // 如果有注释且需要显示，绘制注释
      if (span.note != null && showNotes) {
        _drawNote(canvas, box, span);
      }
    }
  }

  void _drawUnderline(Canvas canvas, TextBox box, TextSpanDecoration span) {
    final paint = Paint()
      ..color = span.color
      ..strokeWidth = span.thickness;

    final y = box.bottom + span.spacing;

    switch (span.style) {
      case UnderlineStyle.solid:
        canvas.drawLine(
          Offset(box.left, y),
          Offset(box.right, y),
          paint,
        );
        break;

      case UnderlineStyle.dashed:
        _drawDashedLine(canvas, box.left, box.right, y, paint);
        break;

      case UnderlineStyle.dotted:
        _drawDottedLine(canvas, box.left, box.right, y, paint);
        break;

      case UnderlineStyle.wavy:
        _drawWavyLine(canvas, box.left, box.right, y, paint);
        break;
    }
  }

  void _drawNote(Canvas canvas, TextBox box, TextSpanDecoration span) {
    final notePainter = TextPainter(
      text: TextSpan(text: span.note, style: noteStyle),
      textDirection: TextDirection.ltr,
    );

    notePainter.layout();

    // 使用 right - left 计算宽度
    final boxWidth = box.right - box.left;
    final x = box.left + (boxWidth - notePainter.width) / 2;

    final y = span.notePosition == NotePosition.above
        ? box.top - span.noteSpacing - notePainter.height
        : box.bottom + span.noteSpacing;

    notePainter.paint(canvas, Offset(x, y));
  }

  void _drawDashedLine(Canvas canvas, double left, double right, double y, Paint paint) {
    final dashWidth = paint.strokeWidth * 4;
    final dashSpace = paint.strokeWidth * 2;
    var currentX = left;

    while (currentX < right) {
      canvas.drawLine(
        Offset(currentX, y),
        Offset(currentX + dashWidth, y),
        paint,
      );
      currentX += dashWidth + dashSpace;
    }
  }

  void _drawDottedLine(Canvas canvas, double left, double right, double y, Paint paint) {
    final spacing = paint.strokeWidth * 2;
    var currentX = left;

    while (currentX < right) {
      canvas.drawCircle(
        Offset(currentX, y),
        paint.strokeWidth / 2,
        paint,
      );
      currentX += spacing;
    }
  }

  void _drawWavyLine(Canvas canvas, double left, double right, double y, Paint paint) {
    final path = Path();
    final waveHeight = paint.strokeWidth * 2;
    final waveWidth = paint.strokeWidth * 4;
    var currentX = left;

    path.moveTo(currentX, y);

    var up = true;
    while (currentX < right) {
      currentX += waveWidth;
      path.quadraticBezierTo(
        currentX - waveWidth / 2,
        y + (up ? -waveHeight : waveHeight),
        currentX,
        y,
      );
      up = !up;
    }

    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant TextDecorationPainter oldDelegate) {
    return text != oldDelegate.text ||
        spans != oldDelegate.spans ||
        textStyle != oldDelegate.textStyle ||
        noteStyle != oldDelegate.noteStyle ||
        minLineSpacing != oldDelegate.minLineSpacing ||
        showNotes != oldDelegate.showNotes;
  }
}